<template>
  <view class="fg-style">
    <u-form
      ref="generateForm"
      :model="model"
      :rules="rules"
      :error-type="['toast']"
      label-position="top"
      :label-align="widgetForm.config.labelAlign"
    >
      <u-row :gutter="16">
        <template
          v-for="(element, index) of widgetForm.list"
          :key="element.key"
        >
          <u-col v-if="element.options.visibleFlag" :span="12">
            <template v-if="element.type === 'grid'">
              <div
                v-for="(item, i) in element.columns"
                :key="i"
                style="display: flex; align-items: center"
              >
                <u-row
                  v-if="element.key"
                  :key="element.key"
                  style="flex: 1"
                  type="flex"
                  :gutter="element.options.gutter ?? 0"
                  :justify="element.options.justify"
                  :align="element.options.align"
                >
                  <u-col
                    v-for="(col, colIndex) of item"
                    :key="colIndex"
                    :span="12"
                  >
                    <template v-for="colItem of col.list" :key="colItem.key">
                      <AntdGenerateFormItem
                        v-if="colItem.options.visibleFlag"
                        :model="model"
                        :element="colItem"
                        :config="data.config"
                        :disabled="
                          disabled ||
                          disabledFieldCodes.includes(colItem.fieldCode)
                        "
                        :remote-replace="remoteReplace"
                        @change="(val:any) => itemOptionChange(val, i)"
                      />
                    </template>
                  </u-col>
                </u-row>
                <div class="btn-group">
                  <!-- <Icon size="24" @click="add(element, i)">
                    <AddCircle color="#0177fd" />
                  </Icon> -->
                  <u-icon
                    name="plus-circle-fill"
                    color="#0177fd"
                    size="24"
                    @click="add(element, i)"
                  ></u-icon>
                  <!-- <Icon size="24" @click="reduce(element, i)">
                    <RemoveCircle color="#0177fd" />
                  </Icon> -->
                  <u-icon
                    name="minus-circle-fill"
                    color="#0177fd"
                    size="24"
                    @click="reduce(element, i)"
                  ></u-icon>
                </div>
              </div>
            </template>
            <template v-else-if="element.type === 'fixedCombination'">
              <GenerateFixedCombination
                :model="model"
                :approval-permission="approvalPermission"
                :element="widgetForm.list[index]"
                :config="data.config"
                :disabled="
                  disabled ||
                  disabledFieldCodes.includes(widgetForm.list[index].fieldCode)
                "
                :remote-replace="remoteReplace"
              />
            </template>
            <AntdGenerateFormItem
              v-else
              :key="element.key"
              :model="model"
              :element="widgetForm.list[index]"
              :config="data.config"
              :disabled="
                disabled ||
                disabledFieldCodes.includes(widgetForm.list[index].fieldCode)
              "
              :remote-replace="remoteReplace"
              @change="itemOptionChange"
            />
          </u-col>
        </template>
      </u-row>
    </u-form>
  </view>
</template>

<script lang="ts">
import { defineComponent, onMounted, reactive, toRefs, watch } from 'vue';
import AntdGenerateFormItem from './AntdGenerateFormItem.vue';
import {
  antd,
  getDatePickerFormat,
  convertFieldValueToShow,
  getValueByModel,
} from './config';
import { fieldType } from './config/enum';
import { v4 } from 'uuid';
// import { randomRange } from '@/utils/index'
import { cloneDeep } from 'lodash-es';
import GenerateFixedCombination from './GenerateFixedCombination.vue';
import { onReady } from '@dcloudio/uni-app';
// TODO: 用setup语法糖模式重写一下吧
export default defineComponent({
  name: 'AntdGenerateForm',
  components: {
    AntdGenerateFormItem,
    GenerateFixedCombination,
  },
  props: {
    data: {
      type: Object,
      default: antd.widgetForm,
    },
    isShow: {
      type: Boolean,
      default: false,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    remoteReplace: {
      type: Object,
      required: true,
    },
    disabledFieldCodes: {
      type: Array,
      default: () => [],
    },
    queryValueFlag: {
      // 是否查询字段的值
      type: Boolean,
      default: false,
    },
    presetValues: {
      // 表单预置值
      type: Object,
      required: false,
      default: () => ({}),
    },
    approvalPermission: {
      // 审批状态
      type: Boolean,
      default: false,
    },
  },
  emits: ['change'],
  setup(props, context) {
    const state = reactive({
      generateForm: null as any,
      model: {} as any,
      rules: {} as any,
      widgetForm: (props.data && cloneDeep(props.data)) ?? antd.widgetForm,
    });

    // 下拉框的联动事件
    const itemOptionChange = (data: any, index: any) => {
      const { element, value } = data;
      if (element.options.linkContent && element.options.linkContent.length) {
        element.options.linkContent.forEach((el: any) => {
          if (el.optionVal === value) {
            el.linkedFields.forEach((fieldModelItem: any) => {
              if (element.parentKey) {
                // parentKey为循环事件的id，如果存在，则只需要控制当前行的其他子组件即可
                const gridItem = state.widgetForm.list.find(
                  (e: any) => e.key === element.parentKey
                );
                const item = gridItem.columns[index].find(
                  (e: any) =>
                    e.list[0].defaultKey === fieldModelItem.linkFrontId
                );
                if (item) {
                  item.list[0].options.visibleFlag = fieldModelItem.visibleFlag;
                }
              } else {
                // parentKey不存在就直接控制表单内的第一层组件
                const item = state.widgetForm.list.find(
                  (e: any) => e.key === fieldModelItem.linkFrontId
                );
                if (item) {
                  item.options.visibleFlag = fieldModelItem.visibleFlag;
                }
              }
            });
          }
        });
      }
      if (element.options.attr === 1) {
        // 字段属性为业务字段，通知父组件发生变化
        const val: any = {};
        val[element.fieldCode] = value;
        context.emit('change', val);
      }
    };

    /**
     * 获取字段值
     */
    const getFieldValue = (field: any) => {
      return props.queryValueFlag
        ? field.options.valueContextObj
        : field.options.defaultVal;
    };
    /**
     * 设置值（通过监听表单预设值）
     */
    const setValByWatchPresetValues = () => {
      if (!props.presetValues || !state.widgetForm.list) {
        return;
      }
      for (const item of state.widgetForm.list) {
        if (item.options.attr !== 1) {
          continue;
        }
        if (item.fieldCode in props.presetValues) {
          state.model[item.model] = cloneDeep(
            props.presetValues[item.fieldCode]
          );
        }
        setLinkedFieldVisiable(item);
      }
    };

    const generateModel = (list: any[]) => {
      for (let index = 0; index < list.length; index++) {
        const model = list[index].model;
        if (!model) {
          return;
        }
        setFieldValue(list[index], model);
        setFieldRules(list[index], model);
        setLinkedFieldVisiable(list[index]);
        setValByWatchPresetValues();
      }
    };

    /**
     * 设置字段值
     */
    const setFieldValue = (field: any, model: any) => {
      if (field.type === 'grid') {
        field.columns[0].forEach((col: any) => generateModel(col.list));
      } else if (field.type === 'text') {
        // 说明文字不作处理
      } else {
        state.model[model] = convertModelToShow(field);
      }
    };

    /**
     * 转换值格式
     */
    const convertModelToShow = (field: any) => {
      const fieldValue = getFieldValue(field);
      const fieldObj = {
        fieldType: field.fieldType,
        valueContextObj: fieldValue,
        multipleFlag: field.options.multipleFlag,
      };
      return convertFieldValueToShow(fieldObj);
    };

    /**
     * 设置字段的校验规则
     */
    const setFieldRules = (field: any, model: any) => {
      if (
        field.fieldType === fieldType.text ||
        field.fieldType === fieldType.cycleEvent ||
        field.fieldType === fieldType.fixedCombination
      ) {
        return;
      }
      const required = field.options.rules.required ? true : false;
      if (field.fieldType === fieldType.singleLineText) {
        const rules = [
          { required: required, validator: checkInput, trigger: 'blur' },
        ];
        state.rules[model] = rules;
        return;
      }
      if (field.fieldType === fieldType.multiLineText) {
        const rules = [
          { required: required, validator: checkTextarea, trigger: 'blur' },
        ];
        state.rules[model] = rules;
        return;
      }
      if (field.fieldType === fieldType.number) {
        const rules = [
          {
            required: required,
            validator: checkNumber,
            trigger: 'blur',
            type: 'number',
          },
        ];
        state.rules[model] = rules;
        return;
      }
      if (field.fieldType === fieldType.radio) {
        const rules = [
          { required: required, validator: checkRadio, trigger: 'change' },
        ];
        state.rules[model] = rules;
        return;
      }
      if (field.fieldType === fieldType.checkbox) {
        const rules = [
          { required: required, validator: checkCheckbox, trigger: 'change' },
        ];
        state.rules[model] = rules;
        return;
      }
      if (field.fieldType === fieldType.select) {
        const rules = [
          { required: required, validator: checkSelect, trigger: 'change' },
        ];
        state.rules[model] = rules;
        return;
      }
      if (field.fieldType === fieldType.cascader) {
        const rules = [
          { required: required, validator: checkCascader, trigger: 'change' },
        ];
        state.rules[model] = rules;
        return;
      }
      if (field.fieldType === fieldType.dateTime) {
        const rules = [
          { required: required, validator: checkDateTime, trigger: 'change' },
        ];
        state.rules[model] = rules;
        return;
      }
      if (field.fieldType === fieldType.upload) {
        const rules = [
          { required: required, validator: checkUpload, trigger: 'change' },
        ];
        state.rules[model] = rules;
      }
      state.generateForm.setRules(state.rules);
      console.log('rules', state.rules);
    };

    /**
     * 设置被联动字段的显示隐藏
     */
    const setLinkedFieldVisiable = (data: any) => {
      const value = getValueByModel(state.model[data.model], data);
      if (value === undefined || value === null || value === '') {
        return;
      }
      if ('radio' === data.type) {
        itemOptionChange({ element: data, value }, 0);
      }
      if ('select' === data.type && 1 === data.options.remote) {
        // 固定选项的下拉框
        for (const val of value) {
          itemOptionChange({ element: data, value: val }, 0);
        }
      }
    };

    // 获取组件选项（下拉，单选，多选）
    const generateOptions = (list: any[]) => {
      list.forEach((item) => {
        if (item.type === 'grid') {
          item.columns[0].forEach((col: any) => generateOptions(col.list));
        } else if (item.options.remote === 2) {
        }
      });
    };

    watch(
      () => props.isShow,
      (val) => {
        if (!val) {
          return;
        }
        state.widgetForm =
          (props.data && cloneDeep(props.data)) ?? antd.widgetForm;
        state.model = {};
        state.rules = {};
        generateModel(state.widgetForm.list);
        generateOptions(state.widgetForm.list);
      },
      { deep: true, immediate: true }
    );

    watch(
      () => props.presetValues,
      () => {
        setValByWatchPresetValues();
      },
      { deep: true, immediate: true }
    );

    onReady(() => {
      generateModel(state.widgetForm?.list ?? []);
      generateOptions(state.widgetForm?.list ?? []);
    });

    /**
     * 获取表单填写数据
     */
    const getData = (isValidate = true) => {
      return new Promise((resolve) => {
        if (isValidate) {
          state.generateForm.validate((validate: boolean) => {
            console.log('validate', validate);
            if (validate) {
              resolve(convertSubmitData());
            }
          });
        } else {
          resolve(convertSubmitData());
        }
      });
    };

    // 转换提交数据格式
    const convertSubmitData = () => {
      const data: any[] = [];
      for (const key in state.model) {
        const field = getFieldByFieldId(key);
        if (!field) {
          continue;
        }
        const tempItem: any = {
          fieldId: key,
          visibleFlag: field.options.visibleFlag,
        };
        if (field.type !== 'text') {
          const value = getValueByModel(state.model[key], field);
          tempItem.valueContextObj = convertValueToSubmit(field, value);
        }
        data.push(tempItem);
      }
      return data;
    };

    /**
     * 转换默认值格式
     */
    const convertValueToSubmit = (localField: any, value: any) => {
      if (
        [
          fieldType.singleLineText,
          fieldType.multiLineText,
          fieldType.dateTime,
        ].includes(localField.fieldType)
      ) {
        return { stringVal: value };
      } else if (localField.fieldType === fieldType.number) {
        if (value === undefined || value === null || value === '') {
          return { stringVal: null };
        }
        return { stringVal: value };
      } else if (localField.fieldType === fieldType.radio) {
        return convertRadioToSubmit(localField, value);
      } else if (localField.fieldType === fieldType.checkbox) {
        return convertCheckboxToSubmit(localField, value);
      } else if (localField.fieldType === fieldType.select) {
        return convertSelectToSubmit(localField, value);
      } else if (localField.fieldType === fieldType.upload) {
        return convertUploadToSubmit(value);
      } else if (localField.fieldType === fieldType.cascader) {
        return convertCascaderToSubmit(value);
      } else if (localField.fieldType === fieldType.fixedCombination) {
        return { comboVal: value };
      }
      return null;
    };

    /**
     * 转换单选的值
     */
    const convertRadioToSubmit = (localField: any, value: any) => {
      if (value) {
        const option = localField.options.options.find(
          (opt: any) => opt.value === value
        );
        if (option) {
          return { optionVal: { value: option.value, label: option.label } };
        }
      }
      return { optionVal: null };
    };

    /**
     * 转换多选的值
     */
    const convertCheckboxToSubmit = (localField: any, value: any) => {
      if (!value) {
        return { optionsVal: null };
      }
      const tempArr: any = [];
      for (const optVal of value) {
        const option = localField.options.options.find(
          (opt: any) => opt.value === optVal
        );
        if (option) {
          tempArr.push({ value: option.value, label: option.label });
        }
      }
      if (tempArr.length > 0) {
        return { optionsVal: tempArr };
      }
      return { optionsVal: null };
    };

    /**
     * 转换下拉选择的值
     */
    const convertSelectToSubmit = (localField: any, value: any) => {
      if (!value) {
        return { optionsVal: null };
      }
      const optionArr =
        localField.options.remote === 1
          ? localField.options.options
          : localField.options.remoteOptions;
      const valueArr = localField.options.multipleFlag ? value : [value];
      const tempArr: any = [];
      for (const optVal of valueArr) {
        const option = optionArr.find((opt: any) => opt.value === optVal);
        if (option) {
          tempArr.push({
            value: option.value,
            label: option.label,
            fullLabel: option.fullLabel,
          });
        }
      }
      if (tempArr.length > 0) {
        return { optionsVal: tempArr };
      }
      return { optionsVal: null };
    };

    /**
     * 转换文件上传的值
     */
    const convertUploadToSubmit = (value: any) => {
      if (value) {
        const fileArr = value.map((item: any) => {
          return {
            fileId: item.uid,
            fileName: item.name,
            fileSize: item.size,
          };
        });
        if (fileArr.length > 0) {
          return { fileUploadVal: fileArr };
        }
      }
      return { fileUploadVal: null };
    };

    /**
     * 转换级联的值
     */
    const convertCascaderToSubmit = (value: any) => {
      if (!value) {
        return { optionsVal: null };
      }
      const tempArr: any = [];
      for (const optVal of value) {
        tempArr.push({ value: optVal });
      }
      if (tempArr.length > 0) {
        return { optionsVal: tempArr };
      }
      return { optionsVal: null };
    };

    /**
     * 转换业务数据
     */
    const convertBusinessData = () => {
      const businessData: any = {};
      for (const field of state.widgetForm.list) {
        if (field.fieldCode && field.model) {
          businessData[field.fieldCode] = getValueByModel(
            state.model[field.model],
            field
          );
        }
      }
      return businessData;
    };

    /**
     * 获取业务数据
     */
    const getBusinessData = (isValidate = true) => {
      return new Promise((resolve, reject) => {
        if (isValidate) {
          state.generateForm.validate((validate: boolean) => {
            if (validate) {
              resolve(convertBusinessData());
            }
          });
        } else {
          resolve(convertBusinessData());
        }
      });
    };

    const reset = () => {
      state.generateForm.resetFields();
    };

    // 循环事件（加）
    const add = (el: any, i: number) => {
      const tempItem = cloneDeep(el);
      tempItem.columns[i].forEach((element: any) => {
        element.list.forEach((item: any) => {
          const key = v4().replaceAll('-', '');
          item.key = key;
          item.model = `${key}`;
        });
      });
      el.columns.splice(i + 1, 0, tempItem.columns[i]);
    };
    // 循环事件（减）
    const reduce = (el: any, i: number) => {
      if (el.columns.length === 1) {
        uni.showToast({
          title: '至少保留一行',
          icon: 'none',
          duration: 2000,
        });
        return;
      }
      el.columns.splice(i, 1);
    };

    /**
     * 根据字段Id查询字段Obj
     */
    const getFieldByFieldId = (fieldId: any) => {
      return state.widgetForm.list.find((temp: any) => fieldId === temp.model);
    };

    /**
     * 根据校验规则查询字段Obj
     */
    const getFieldByRule = (_rule: any) => {
      return getFieldByFieldId(_rule.field);
    };

    /**
     * 校验输入框
     */
    const checkInput = async (_rule: any, value: string) => {
      const field = getFieldByRule(_rule) || { options: {} };
      if (value) {
        if (value.length > field.options.maxlength) {
          return Promise.reject(
            field.fieldName + '内容长度限制为' + field.options.maxlength
          );
        }
        if (field.options.format === 2) {
          // 仅允许填写手机号和座机
          if (/^((0\d{2,3}-\d{7,8})|(1[3456789]\d{9}))$/.test(value)) {
            return Promise.resolve();
          }
          return Promise.reject('请输入正确的手机号或座机');
        } else if (field.options.format === 3) {
          // 仅允许填写邮箱
          if (/^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(value)) {
            return Promise.resolve();
          }
          return Promise.reject('请输入正确的邮箱');
        }
        return Promise.resolve();
      }
      if (_rule.required) {
        // 必填
        return Promise.reject('请输入' + field.fieldName);
      }
      return Promise.resolve();
    };

    /**
     * 校验多行文本
     */
    const checkTextarea = async (_rule: any, value: string) => {
      const field = getFieldByRule(_rule) || { options: {} };
      if (value) {
        if (value.length > field.options.maxlength) {
          return Promise.reject(
            field.fieldName + '内容长度限制为' + field.options.maxlength
          );
        }
        return Promise.resolve();
      }
      if (_rule.required) {
        // 必填
        return Promise.reject('请输入' + field.fieldName);
      }
      return Promise.resolve();
    };

    /**
     * 校验数值
     */
    const checkNumber = async (_rule: any, value: number) => {
      const field = getFieldByRule(_rule) || { options: {} };
      if (value !== undefined && value !== null) {
        if (value < field.options.min) {
          return Promise.reject(
            field.fieldName + '最小值为' + field.options.min
          );
        }
        if (value > field.options.max) {
          return Promise.reject(
            field.fieldName + '最大值为' + field.options.max
          );
        }
        if (field.options.decimalPoint === 0) {
          if (Number.isInteger(value)) {
            return Promise.resolve();
          }
          return Promise.reject('必须为整数');
        } else if (field.options.decimalPoint === 1) {
          if (/^[+-]?\d+(?:\.\d{0,1})?$/.test(String(value))) {
            return Promise.resolve();
          }
          return Promise.reject('小数点后最多一位小数');
        } else if (field.options.decimalPoint === 2) {
          if (/^[+-]?\d+(?:\.\d{0,2})?$/.test(String(value))) {
            return Promise.resolve();
          }
          return Promise.reject('小数点后最多两位小数');
        }
        return Promise.resolve();
      }
      if (_rule.required) {
        // 必填
        return Promise.reject('请输入' + field.fieldName);
      }
      return Promise.resolve();
    };

    /**
     * 校验单选框
     */
    const checkRadio = async (_rule: any, value: string) => {
      const field = getFieldByRule(_rule) || { options: {} };
      if (_rule.required) {
        if (value) {
          return Promise.resolve();
        }
        // 必填
        return Promise.reject('请选择' + field.fieldName);
      }
      return Promise.resolve();
    };

    /**
     * 校验复选框
     */
    const checkCheckbox = async (_rule: any, value: []) => {
      const field = getFieldByRule(_rule) || { options: {} };
      if (_rule.required) {
        if (value && value.length > 0) {
          return Promise.resolve();
        }
        // 必填
        return Promise.reject('请选择' + field.fieldName);
      }
      return Promise.resolve();
    };

    /**
     * 校验选择框
     */
    const checkSelect = async (_rule: any, value: {} | []) => {
      const field = getFieldByRule(_rule) || { options: {} };
      const val = getValueByModel(value, field);
      if (_rule.required) {
        if (val && val.length > 0) {
          return Promise.resolve();
        }
        // 必填
        return Promise.reject('请选择' + field.fieldName);
      }
      return Promise.resolve();
    };

    /**
     * 校验级联
     */
    const checkCascader = async (_rule: any, value: string | []) => {
      const field = getFieldByRule(_rule) || { options: {} };
      if (_rule.required) {
        if (value && value.length > 0) {
          return Promise.resolve();
        }
        // 必填
        return Promise.reject('请选择' + field.fieldName);
      }
      return Promise.resolve();
    };

    /**
     * 校验日期时间选择
     */
    const checkDateTime = async (_rule: any, value: string | []) => {
      const field = getFieldByRule(_rule) || { options: {} };
      if (_rule.required) {
        if (value && value.length > 0) {
          return Promise.resolve();
        }
        // 必填
        return Promise.reject('请选择' + field.fieldName);
      }
      return Promise.resolve();
    };

    /**
     * 校验文件上传
     */
    const checkUpload = async (_rule: any, value: []) => {
      const field = getFieldByRule(_rule) || { options: {} };
      if (_rule.required && (!value || value.length < 1)) {
        return Promise.reject('请上传文件');
      }
      if (field.options.attachmentNumber === 0) {
        return Promise.resolve();
      }
      if (
        value &&
        value.length !== 0 &&
        value.length !== Number(field.options.attachmentNumber)
      ) {
        return Promise.reject('上传数量不匹配');
      }
      return Promise.resolve();
    };
    return {
      ...toRefs(state),
      getData,
      reset,
      add,
      reduce,
      itemOptionChange,
      getDatePickerFormat,
      getBusinessData,
    };
  },
});
</script>
<style lang="scss" scoped>
.fg-style {
  padding-left: 10rpx;
}
:deep(.btn-group) {
  span {
    cursor: pointer;
  }
}
</style>
